home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BBS in a Box 7
/
BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso
/
Files
/
Tele
/
C
/
Comet2.1.3.cpt
/
Comet
/
mactcp.c
< prev
next >
Wrap
Text File
|
1991-08-16
|
31KB
|
1,414 lines
/* Copyright Cornell University 1986. All rights are reserved. */
/* See permission and disclaimer notice in file "notice.h" */
/* 10/6/89 kevin rewrote to use a circular buffer */
/* 11/27/89 kevin tried to fix hang problem by checking emdp->connopen before read */
/* 12/1/89 kevin modified so stream is released after every session */
#define MACTCP
#include <em.h>
#include "tftp.h"
#include <menudefs.h>
#include <resdefs.h>
#include <net.h>
#include "mactcp.h"
#ifndef NULL
#define NULL 0L
#endif
#include <util.h>
char * ippname = "\P.IPP"; /* name of IP driver */
short ipp_refnum; /* refnum of IP driver */
unsigned short maxseg = SENDBUFHIGH; /* maximum segment size */
short mactcpurgent; /* urgent flag */
TCPiopb statblk; /* statistics */
TCPiopb tcp_read; /* Read control block */
short read_req;
short read_reread;
short read_comp;
short read_upcalled;
short read_badreturns;
short read_callfail;
short read_fail;
struct rdsstruct {
rdsEntry rdstab[RDSSIZE];
unsigned short wdsend; /* left zero to end RDS */
} read_wds;
/* tcppb is an array of control blocks for sends */
struct tcppb {
TCPiopb pb; /* Mac parameter block for writes */
wdsEntry wds1; /* standard wds */
wdsEntry wds2; /* wds for use if buffer has wrapped */
short wdsend; /* always 0 */
struct winds * twp; /* the sending window */
short busy; /* the pb is in use */
} tcppb[PBCOUNT];
short send_pend; /* # of sends pending completion */
short send_next; /* index of next free PB */
short send_req;
short send_comp;
short send_fail;
void mts_done(); /* send completion vector */
void mtr_done(); /* read completion vector */
void mtip_done(); /* ip init completion vector */
void mtcl_done(); /* ip init completion vector */
void mtopen_done(); /* ip init completion vector */
timer *tcp_tm; /* timer for attempting resend if out of buffers */
char readup; /* an async read has been performed */
extern char *malloc();
extern unsigned long getmyA5();
#define MTVALIDITY
#define PROMPTSEND
#define ipctlGetAddr 15
/* MPW uses d0/d1/a0/a1 as scratch so we must preserve Aztec scratch regs
just in case
*/
#asm
mpwcregs reg d0-d3/a0-a2
#endasm
/* the TCP Async Notification Routine */
pascal void tcp_event(stream, eventCode, conp, terminReason, icmpMsg)
StreamPtr stream;
short eventCode;
struct winds * conp;
short terminReason;
ICMPReport *icmpMsg;
{
unsigned long oldA5;
oldA5 = getmyA5();
if (invalidconn(conp)) {
/* check to make sure the UserDataPtr points to a real window */
SysBeep(1);
if (keydp != NULL) {
prerrint25(keydp, "Received upcall from MacTCP for non-existent connection");
}
setA5(oldA5);
return;
}
mtevent = TRUE;
switch (eventCode) {
case TCPClosing: {
if (!conp->closeflag)
conp->closeflag = TRUE;
break;
}
case TCPULPTimeout: {
prerrint25(conp, "TCP Timeout");
break;
}
case TCPTerminate: {
if (conp->mtcpconnopen) {
conp->closeflag = terminReason;
conp->mtcpconnopen = FALSE; /* connection no longer exists */
if (!conp->closeflag) {
conp->closeflag = TRUE;
}
}
break;
}
case TCPDataArrival: {
conp->data_rcvd = TRUE;
break;
}
case TCPUrgent: {
break;
}
case TCPICMPReceived: {
/*
prerrint25(conp, "TCP ICMP Packet Received");
*/
break;
}
default: {
prerrint25(conp, "Unknown TCP Notify Code received");
break;
}
}
setA5(oldA5);
}
/* TODO these asynchronous routines are not reliable in MacTCP
as of 1.0.1.
Multiple outstanding sends cause crashes on Mac+, so we
better not use 'em anyway.
Async sends seem to cause problems on LocalTalk.
Could be problems w/ MPW v C on args....
OR could MacTCP be failing to save a1 (d1, d2) when making
direct trap calls after a GetTrapAddress?
*/
void mtip_done(tcppb)
TCPiopb *tcppb;
{
unsigned long oldA5;
oldA5 = getmyA5();
#asm
movem.l mpwcregs,-(a7)
#endasm
if (tcp_read.ioResult) {
ipp_refnum = tcp_read.ioCRefNum;
macipopen = TRUE;
}
#asm
movem.l (a7)+,mpwcregs
#endasm
setA5(oldA5);
}
void mts_done(tcb)
TCPiopb *tcb;
{
wdsEntry *wds;
unsigned long oldA5;
struct tcppb * tcppbp;
oldA5 = getmyA5();
#asm
movem.l mpwcregs,-(a7)
#endasm
#ifdef DYNAMICPB
tcppbp = (struct tcppb *) tcb->csParam.send.userDataPtr;
#else
tcppbp = (struct tcppb *) tcb;
#endif
wds = (wdsEntry *) tcb->csParam.send.wdsPtr;
if (tcb->ioResult) {
send_fail++;
/* prerrint25(twp, "send failure"); */
}
else {
/* subtract the acked data from the count in the buffer */
tcppbp->twp->fillcount -= wds->length;
wds++; /* -> wds2 */
tcppbp->twp->fillcount -= wds->length;
send_comp++;
}
--send_pend;
tcppbp->busy = FALSE;
#asm
movem.l (a7)+,mpwcregs
#endasm
setA5(oldA5);
}
#ifdef ASYNCCLOSE
void mtcl_done(tcppb)
TCPiopb *tcppb;
{
unsigned long oldA5;
struct winds * twp;
oldA5 = getmyA5();
#asm
movem.l mpwcregs,-(a7)
#endasm
twp = (struct winds *) tcppb->csParam.send.userDataPtr;
twp->mtcpconnopen = FALSE;
#asm
movem.l (a7)+,mpwcregs
#endasm
setA5(oldA5);
}
#endif
#ifdef ASYNCOPEN
void mtopen_done(tcppb)
TCPiopb *tcppb;
{
unsigned long oldA5;
struct winds * twp;
oldA5 = getmyA5();
#asm
movem.l mpwcregs,-(a7)
#endasm
twp = (struct winds *) tcppb->csParam.send.userDataPtr;
if (tcppb->ioResult == openFailed) {
tcp_err(tcppb->ioResult);
twp->closeflag = -2;
return(1);
}
else if (tcppb->ioResult) {
tcp_err(tcppb->ioResult);
twp->closeflag = -2;
return(1);
}
twp->openflag = TRUE;
twp->mtcpconnopen = TRUE;
mtevent = TRUE;
/* opn_usr() will be called asynchronously */
#asm
movem.l (a7)+,mpwcregs
#endasm
setA5(oldA5);
}
#endif
tcp_upcall()
{
short index;
OSErr errcode;
readup = FALSE;
emdp->data_rcvd = FALSE;
tcp_read.tcpStream = emdp->tcp_stream;
tcp_read.csCode = TCPNoCopyRcv;
PBControl(&tcp_read, (Boolean) FALSE);
if (tcp_read.ioResult) {
read_fail++;
if (emdp->mtcpconnopen) {
/* ASYNC read always fails once connection broken */
tcp_err(tcp_read.ioResult);
}
}
else {
for (index = 0; read_wds.rdstab[index].length; index++) {
wr_usr(read_wds.rdstab[index].ptr, read_wds.rdstab[index].length);
}
read_upcalled++;
}
/* free the buffers we read */
tcp_read.csCode = TCPRcvBfrReturn;
if (errcode = PBControl(&tcp_read, (Boolean) FALSE)) {
read_badreturns++;
}
}
/* SHOULD open the Internet Packet driver asynchronously
so we can do other stuff BUT doesn't seem to call completion! */
ParamBlkRec openblk;
macip_init()
{
/* use the openblk block to save some space */
TCPiopb infoblk;
if (macipopen)
return(0);
openblk.ioNamePtr = (StringPtr) ippname;
openblk.u.iop.ioPermssn = 0; /* ioPermssn field */
/* fsRdWrPerm seems to cause crash...*/
#ifdef IPASYNC
openblk.ioCompletion = mtip_done;
PBOpen(&openblk, (Boolean) TRUE);
#else
#ifdef OPENDRIVER
if (OpenDriver(ippname, &ipp_refnum)) {
error("Can't open MacTCP; check MacTCP configuration for correct net #, gateway address, and unique node address");
return(-1);
}
#else
openblk.ioCompletion = NULL;
PBOpen(&openblk, (Boolean) FALSE);
if (openblk.ioResult) {
error("Can't open MacTCP; check MacTCP configuration for correct net #, gateway address, and unique node address");
return(-1);
}
ipp_refnum = openblk.u.iop.ioRefNum;
#endif
macipopen = TRUE;
/* get our IP address */
memzero(&infoblk, sizeof(struct TCPiopb));
infoblk.ioCRefNum = ipp_refnum;
infoblk.csCode = ipctlGetAddr;
PBControl(&infoblk, (Boolean) FALSE);
if (infoblk.ioResult) {
rnet->ip_addr = 0;
}
else
rnet->ip_addr = infoblk.tcpStream;
/* kluge to avoid defining GetMyIPAddr pb */
#endif
return(0);
}
mactcp_init()
{
short cnt;
TCPiopb infoblk;
if (mactcpopen)
return(0);
if (!macipopen) {
if (macip_init()) {
return(-1);
}
}
memzero(&infoblk, sizeof(struct TCPiopb));
/* allocate resend retry timer */
if (tcp_tm == NULL) {
/* first time through */
if ((tcp_tm = tm_alloc()) == NULL)
return(-1);
}
#ifdef IPASYNC
while (openblk.ioResult == 1)
;
/* wait for async IP init to complete */
if (openblk.ioResult) {
error("Can't open MacTCP driver");
return(-1);
}
ipp_refnum = openblk.ioCRefNum;
#endif
tcp_read.ioNamePtr = (StringPtr) NULL;
infoblk.ioCRefNum = ipp_refnum;
infoblk.csCode = TCPGlobalInfo;
/* get MSS. NB: MacTCP hangs if send WDS is > MSS!!!!! */
if (PBControl(&infoblk, (Boolean) FALSE)) {
error("Can't get MacTCP MSS, using 512 default");
}
else
maxseg = infoblk.csParam.globalInfo.tcpParamPtr->tcpMaxSegSize;
/* set up read PB */
tcp_read.ioCRefNum = ipp_refnum;
tcp_read.csCode = TCPNoCopyRcv;
tcp_read.csParam.receive.rdsPtr = (Ptr) &read_wds;
tcp_read.csParam.receive.rdsLength = RDSSIZE;
tcp_read.ioCompletion = NULL;
tcp_read.csParam.receive.commandTimeoutValue = 1;
/* allocate send pbs */
for (cnt = 0; cnt < PBCOUNT; cnt++) {
#ifdef DYNAMICPB
tcppb[cnt].pb = (TCPiopb *) malloc(sizeof(struct TCPiopb));
if (tcppb[cnt].pb == NULL) {
return(-1);
}
tcppb[cnt].pb = StripAddress(tcppb[cnt].pb);
memzero(tcppb[cnt].pb, sizeof(struct TCPiopb));
#endif
tcppb[cnt].pb.csCode = TCPSend;
tcppb[cnt].pb.ioCRefNum = ipp_refnum;
tcppb[cnt].pb.ioCompletion = NULL;
#ifdef MTVALIDITY
/* set timeout value */
tcppb[cnt].pb.csParam.send.ulpTimeoutValue = 255;
tcppb[cnt].pb.csParam.send.ulpTimeoutAction = 1; /* was 1, abort */
tcppb[cnt].pb.csParam.send.validityFlags = timeoutValue | timeoutAction;
#endif
tcppb[cnt].pb.csParam.send.pushFlag = TRUE;
tcppb[cnt].pb.csParam.send.wdsPtr = (Ptr) &tcppb[cnt].wds1;
/* setup wds for this PB */
tcppb[cnt].wdsend = 0;
}
mactcpopen = TRUE;
return(0);
}
/* call macTCP to make a stream */
tcp_makestream()
{
/* TCPiopb tblk;
TODO could the allocation of the stream on the stack rather than
permanently be causing problems? probably not ...*/
if (emdp->tcp_stream)
/* we already have a stream allocated */
return(0);
if (emdp->mtstream == NULL) {
/* allocate TCP stream create memory; may not be necessary to save this... */
if ((emdp->mtstream = (char *) malloc(sizeof(struct TCPiopb))) == NULL) {
tcpmemoryreclaim(emdp);
return(-1);
}
emdp->mtstream = StripAddress(emdp->mtstream);
/* allocate send buffer */
emdp->sendbuf = (unsigned char *) malloc(SENDBUFSIZE);
if (emdp->sendbuf == NULL) {
tcpmemoryreclaim(emdp);
return(-1);
}
emdp->sendbuf = StripAddress(emdp->sendbuf);
/* allocate connection block */
emdp->tcp_conn = (TCPiopb *) malloc(sizeof(TCPiopb));
if (emdp->tcp_conn == NULL) {
tcpmemoryreclaim(emdp);
return(-1);
}
emdp->tcp_conn = StripAddress(emdp->tcp_conn);
/* allocate the receive buffer */
if ((emdp->rcvbuf = (char *) malloc(BUFLEN)) == NULL) {
tcpmemoryreclaim(emdp);
return(-1);
}
emdp->rcvbuf = StripAddress(emdp->rcvbuf);
}
/* initialize the elements... */
memzero(emdp->mtstream, sizeof(struct TCPiopb));
emdp->sendp = emdp->fillp = emdp->sendbuf;
emdp->fillendp = emdp->sendbuf + SENDBUFSIZE;
memzero(emdp->tcp_conn, sizeof(struct TCPiopb));
emdp->mtstream->ioCRefNum = ipp_refnum;
emdp->mtstream->csCode = TCPCreate;
emdp->mtstream->csParam.create.rcvBuff = emdp->rcvbuf;
emdp->mtstream->csParam.create.rcvBuffLen = (unsigned long) BUFLEN;
emdp->mtstream->csParam.create.notifyProc = (ProcPtr) tcp_event;
emdp->mtstream->csParam.create.userDataPtr = emdp;
PBControl(emdp->mtstream, (Boolean) FALSE);
if (emdp->mtstream->ioResult) {
tcp_err(emdp->mtstream->ioResult);
tcpmemoryreclaim(emdp);
return(-1);
}
/* we get the stream * in return */
emdp->tcp_stream = emdp->mtstream->tcpStream;
/* if we don't do this assignment, it doesn't work... ??? */
emdp->tcp_stream = StripAddress(emdp->tcp_stream);
return(0);
}
/* add a character to the send buffer */
mactcp_put(thechar)
char thechar;
{
if (!emdp->mtcpconnopen)
return(-1);
if (emdp->fillcount >= SENDBUFSIZE) {
return(-1);
}
/* stick the character in the buffer */
emdp->fillcount++;
emdp->waitcount++;
*emdp->fillp++ = thechar;
if (emdp->fillp >= emdp->fillendp) {
/* wrap around if we're at the end of the buffer */
emdp->fillp = emdp->sendbuf;
}
#ifdef PROMPTSEND
if (emdp->waitcount >= maxseg)
/* send if the buffer gets full */
mactcp_ex();
#endif
return(0);
}
/* add a character to the buffer and send the packet promptly */
mactcp_fput(thechar)
char thechar;
{
if (!emdp->mtcpconnopen)
return(-1);
if (! (emdp->fillcount < SENDBUFSIZE)) {
return(-1);
}
/* stick the character in the buffer */
emdp->fillcount++;
emdp->waitcount++;
*emdp->fillp++ = thechar;
if (emdp->fillp >= emdp->fillendp) {
/* wrap around if we're at the end of the buffer */
emdp->fillp = emdp->sendbuf;
}
mactcp_ex();
return(0);
}
/* the better to trap retries for PB available */
tcp_rex()
{
mactcp_ex();
}
/* send outstanding data */
mactcp_ex()
{
unsigned short sendcount;
unsigned short send2;
if (!emdp->mtcpconnopen)
return(-1);
if (emdp->waitcount == 0) {
/* nothing to send */
emdp->send_wait = FALSE;
return(0);
}
else {
emdp->send_wait = TRUE;
mtevent = TRUE; /* guarantee we get service */
}
if (send_pend >= PBCOUNT) {
/* we don't have a free parameter block, reschedule */
#ifdef TCP_REX
tm_tset(1, tcp_rex, emdp, tcp_tm);
#endif
return(-2);
}
if (tcppb[send_next].busy) {
/* find a free pb */
int sendindex;
for (sendindex = send_next + 1; sendindex < PBCOUNT; sendindex++) {
if (tcppb[sendindex].busy)
continue;
}
if (sendindex == PBCOUNT) {
/* didn't find one yet, wrap around */
for (sendindex = 0; sendindex < send_next; sendindex++) {
if (tcppb[sendindex].busy)
continue;
}
if (sendindex == send_next) {
/* no free pb, shouldn't happen here since PBCOUNT tested */
/* TODO--make a new send buffer? */
return(-3);
}
}
send_next = sendindex;
}
if (emdp->fillp < emdp->sendp)
/* data has wrapped */
sendcount = emdp->fillendp - emdp->sendp;
else
sendcount = emdp->fillp - emdp->sendp;
#ifdef PROMPTSEND
if (sendcount > maxseg) {
/* MacTCP chokes if a segment is > MSS ... */
sendcount = maxseg;
}
#endif
/* per window in send */
tcppb[send_next].twp = emdp;
#ifdef DYNAMICPB
tcppb[send_next].pb.csParam.send.userDataPtr = &tcppb[send_next];
#else
tcppb[send_next].pb.csParam.send.userDataPtr = emdp;
#endif
tcppb[send_next].pb.csParam.send.urgentFlag = mactcpurgent;
tcppb[send_next].pb.tcpStream = emdp->tcp_stream;
tcppb[send_next].wds1.ptr = emdp->sendp;
tcppb[send_next].wds1.length = sendcount;
#ifdef TCPBUFWRAP
if (emdp->fillp < emdp->sendp && sendcount < maxseg) {
/* data wrapped, we can use two elements in the WDS */
/* we can send some of the wrapped data */
/* HOWEVER this is no win, since MacTCP sends two pkts anyway */
send2 = emdp->fillp - emdp->sendbuf;
if ((sendcount + send2) >= maxseg) {
send2 = maxseg - sendcount;
sendcount = maxseg;
}
else {
sendcount += send2;
}
tcppb[send_next].wds2.length = send2;
tcppb[send_next].wds2.ptr = emdp->sendbuf;
tcppb[send_next].wdsend = 0; /* terminate WDS2 */
}
else {
tcppb[send_next].wds2.length = 0; /* terminate WDS1 */
tcppb[send_next].wds2.ptr = NULL;
}
#else
tcppb[send_next].wds2.length = 0; /* terminate WDS1 */
tcppb[send_next].wds2.ptr = NULL;
#endif
send_req++;
if (mtcpsendasync) {
/* if user is configured for async send, do so... */
tcppb[send_next].pb.ioCompletion = mts_done;
tcppb[send_next].busy = TRUE;
if (PBControl(&tcppb[send_next].pb, (Boolean) TRUE)) {
/* TODO retries? just bomb out? */
send_fail++;
tcppb[send_next].busy = FALSE;
tcp_err(tcppb[send_next].pb.ioResult);
return(-1);
}
send_pend++;
if (++send_next >= PBCOUNT)
send_next = 0;
}
else {
/* use the synchronous call, which is a bummer because
it does not return until after the data is acked... */
if (tcppb[send_next].pb.ioCompletion) {
/* who the fuck is tampering with this? */
beartrap();
tcppb[send_next].pb.ioCompletion = NULL;
}
if (PBControl(&tcppb[send_next].pb, (Boolean) FALSE)) {
/* TODO retries? just bomb out? */
send_fail++;
tcp_err(tcppb[send_next].pb.ioResult);
return(-1);
}
if (tcppb[send_next].pb.ioCompletion) {
/* who the fuck is tampering with this? */
beartrap();
tcppb[send_next].pb.ioCompletion = NULL;
}
/* subtract the acked data from the count in the buffer */
emdp->fillcount -= sendcount;
send_comp++;
}
emdp->waitcount -= sendcount;
/* set emdp->sendp -> next char needing send */
emdp->sendp += sendcount;
if (emdp->sendp >= emdp->fillendp) {
/* wrap pointer if necessary */
emdp->sendp -= SENDBUFSIZE;
}
return(0);
}
/* open a connection with a host */
mactcp_open(addr, port)
long * addr;
short port;
/* a short local socket argument is also a parameter, not used w/ mactcp */
{
if (!mactcpopen) {
if (mactcp_init()) {
return(-1);
}
}
if (tcp_makestream())
return(-1);
emdp->tcp_conn->ioCRefNum = ipp_refnum;
emdp->tcp_conn->csCode = TCPActiveOpen;
emdp->tcp_conn->tcpStream = emdp->tcp_stream;
#ifdef MTVALIDITY
emdp->tcp_conn->csParam.open.ulpTimeoutValue = 15; /* was 15 */
emdp->tcp_conn->csParam.open.ulpTimeoutAction = 1; /* abort 1, report 0 */
emdp->tcp_conn->csParam.open.validityFlags = timeoutValue | timeoutAction;
#endif
emdp->tcp_conn->csParam.open.remoteHost = *addr;
emdp->tcp_conn->csParam.open.remotePort = port;
emdp->tcp_conn->csParam.open.localPort = 0; /* let mactcp assign */
emdp->tcp_conn->csParam.open.dontFrag = 1;
emdp->tcp_conn->csParam.open.timeToLive = 0; /* let mactcp assign */
emdp->tcp_conn->csParam.open.security = 0; /* let mactcp assign */
emdp->tcp_conn->csParam.open.optionCnt = 0; /* no IP options */
/* commandTimeoutValue not used as per manual */
emdp->tcp_conn->csParam.open.userDataPtr = emdp;
#ifdef ASYNCOPEN
emdp->tcp_conn->ioCompletion = mtopen_done;
PBControl(emdp->tcp_conn, (Boolean) TRUE);
#else
emdp->tcp_conn->ioCompletion = NULL;
SetCursor(*GetCursor(watchCursor));
/* put up a watch cursor to show this may take some time */
PBControl(emdp->tcp_conn, (Boolean) FALSE);
SetCursor(&arrow);
if (emdp->tcp_conn->ioResult == openFailed) {
tcp_err(emdp->tcp_conn->ioResult);
emdp->closeflag = -2;
return(1);
}
else if (emdp->tcp_conn->ioResult) {
tcp_err(emdp->tcp_conn->ioResult);
emdp->closeflag = -2;
return(1);
}
emdp->mtcpconnopen = TRUE;
opn_usr(); /* this comes after completion if async call */
#endif
return(0);
}
/* stubs
needs to be implemented for mactcp
IcEchoRequest()
{
}
*/
mactcp_close()
{
TCPiopb closePB;
if (!emdp->mtcpconnopen || !emdp->tcp_stream)
return(-1);
/* PBControl(&statblk, (Boolean) FALSE)); get pre-closing status */
memzero(&closePB, sizeof(struct TCPiopb));
closePB.ioCRefNum = ipp_refnum;
closePB.csCode = TCPClose;
closePB.tcpStream = emdp->tcp_stream;
closePB.csParam.close.userDataPtr = emdp;
#ifdef MTVALIDITY
closePB.csParam.close.ulpTimeoutValue = 30; /* was 30 */
closePB.csParam.close.ulpTimeoutAction = 1; /* abort, zero = report */
closePB.csParam.close.validityFlags = timeoutValue | timeoutAction;
#endif
#ifdef ASYNCCLOSE
closePB.ioCompletion = mtcl_done;
if (PBControl(&closePB, (Boolean) TRUE)) {
prerrint25(emdp, "TCP Close call failed");
}
#else
closePB.ioCompletion = NULL;
if (PBControl(&closePB, (Boolean) FALSE)) {
prerrint25(emdp, "TCP Close call failed");
/* make sure user can quit application anyway... */
emdp->mtcpconnopen = FALSE; /* connection no longer exists */
emdp->closeflag = TRUE;
}
else {
emdp->mtcpconnopen = FALSE;
/* statblk.csParam.status.connectionState = CLOSED; fix stat report */
}
#endif
return(0);
}
/* release a stream */
tcp_release(twp)
struct winds * twp;
{
TCPiopb relPB;
if (!twp->tcp_stream)
return(-1);
memzero(&relPB, sizeof(struct TCPiopb));
relPB.ioCRefNum = ipp_refnum;
relPB.csCode = TCPRelease;
relPB.tcpStream = twp->tcp_stream;
relPB.csParam.release.userDataPtr = twp;
if (PBControl(&relPB, (Boolean) FALSE)) {
error("MacTCP stream release failed");
return(-1);
}
twp->tcp_stream = 0;
twp->mtcpconnopen = FALSE;
return(0);
}
/* abort a connection not used? */
mactcpclrsendbuf()
{
TCPiopb abortPB;
if (!emdp->mtcpconnopen)
return(-1);
memzero(&abortPB, sizeof(struct TCPiopb));
abortPB.ioCRefNum = ipp_refnum;
abortPB.csCode = TCPAbort;
abortPB.tcpStream = emdp->tcp_stream;
abortPB.csParam.abort.userDataPtr = emdp;
if (PBControl(&abortPB, (Boolean) FALSE)) {
error("session abort failed");
return(-1);
}
/* mactcp_wrapup(); */
emdp->mtcpconnopen = FALSE;
emdp->closeflag = TRUE;
return(0);
}
/* works only in emdp context */
tcp_err(errcode)
OSErr errcode;
{
switch (errcode) {
case inProgress:
prerrint25(emdp, "I/O in progress");
break;
case ipBadLapErr:
prerrint25(emdp, "bad network configuration");
break;
case ipBadCnfgErr:
prerrint25(emdp, "bad IP configuration error");
break;
case ipNoCnfgErr:
prerrint25(emdp, "missing IP or LAP configuration error");
break;
case ipLoadErr:
prerrint25(emdp, "error in MacTCP load");
break;
case ipBadAddr:
prerrint25(emdp, "error in getting address");
break;
case connectionClosing:
prerrint25(emdp, "connection is closing");
break;
case invalidLength:
prerrint25(emdp, "invalid length");
break;
case connectionExists:
prerrint25(emdp, "request conflicts with existing connection");
break;
case connectionDoesntExist:
prerrint25(emdp, "connection does not exist");
break;
case insufficientResources:
prerrint25(emdp, "insufficient resources to perform request");
break;
case invalidStreamPtr:
prerrint25(emdp, "invalid stream ptr");
break;
case streamAlreadyOpen:
prerrint25(emdp, "stream already open");
break;
case connectionTerminated:
prerrint25(emdp, "connection terminated");
break;
case invalidBufPtr:
prerrint25(emdp, "invalid buffer ptr");
break;
case invalidWDS:
prerrint25(emdp, "invalid WDS");
/* also covers RDS */
break;
case openFailed:
prerrint25(emdp, "Session closed: Can't connect to host");
break;
case commandTimeout:
prerrint25(emdp, "command timed out");
break;
case duplicateSocket:
prerrint25(emdp, "duplicate socket");
break;
/* Error codes from internal IP functions */
case ipDontFragErr:
prerrint25(emdp, "Packet too large to send w/o fragmenting");
break;
case ipDestDeadErr:
prerrint25(emdp, "destination not responding");
break;
case ipNoFragMemErr:
prerrint25(emdp, "no memory to send fragmented pkt");
break;
case ipRouteErr:
prerrint25(emdp, "can't route packet off-net");
break;
case outOfMemory:
prerrint25(emdp, "Out of memory");
break;
default:
prerrint25(emdp, "Unknown TCP error");
break;
}
}
char * mtcptermarr[] = {
"",
"",
"Session closed: Host has abruptly closed session with a Reset",
"Session closed: Network failure",
"Session closed: Security/precedence mismatch",
"Session closed: a timeout has occurred",
"Session closed: an abort has occurred",
"Session closed",
"Session closed: Service failure"
};
term_report(cause)
short cause;
{
int sessionkilled = FALSE;
switch (cause) {
case -2: {
/* our tag for failure to connect */
sessionkilled = TRUE;
break;
}
case 2: {
prerrint25(emdp, mtcptermarr[cause]);
sessionkilled = TRUE;
break;
}
case 3: {
prerrint25(emdp, mtcptermarr[cause]);
sessionkilled = TRUE;
break;
}
case 4: {
prerrint25(emdp, mtcptermarr[cause]);
sessionkilled = TRUE;
break;
}
case 5: {
prerrint25(emdp, mtcptermarr[cause]);
sessionkilled = TRUE;
break;
}
case 6: {
prerrint25(emdp, mtcptermarr[cause]);
sessionkilled = TRUE;
break;
}
case 7: {
/* this is a normal close requested from the user layer */
prerrint25(emdp, mtcptermarr[cause]);
break;
}
case 8: {
prerrint25(emdp, mtcptermarr[cause]);
sessionkilled = TRUE;
break;
}
}
if (sessionkilled) {
/* alert used session died abnormally */
beep();
windmenumark(emdp, 0xA0); /* set a † mark */
}
else
windmenumark(emdp, noMark); /* clear any marks */
}
/* wrap up a MacTCP connection, close if necessary, reset UI */
/* WARNING: twp may disappear & emdp change when this function is called! */
mactcp_wrapup()
{
int theflag = emdp->closeflag;
emdp->closeflag = 0;
term_report(theflag);
if (emdp->mtcpconnopen) {
mactcp_close();
emdp->closeflag = 0; /* could get reset by MacTCP during close? */
}
mtreset();
cls_usr(); /* WARNING: twp may disappear, emdp may change! */
}
/* reset the MacTCP session variables */
mtreset()
{
emdp->fillcount = 0;
emdp->waitcount = 0;
emdp->send_wait = FALSE;
emdp->sendp = emdp->fillp = emdp->sendbuf;
emdp->closeflag = FALSE;
/* no timers allocated for MacTCP */
}
#ifndef DUALTCP
char * strend(sptr)
register char * sptr;
{
while (*sptr++) {
;
}
return(--sptr);
}
#endif
/*
Display some tcp statistics and a few lines of unacked data. Should be
revised and integrated in with the normal logging system.
*/
/* this is now mac-dependent */
#define CLOSED 0
#define SYNRCVD 4
#define SYNSENT 6
#define ESTAB 8
#define FINWAIT1 10
#define FINWAIT2 12
#define CLOSEWAIT 14
#define CLOSING 16
#define LASTACK 18
#define TIMEWAIT 20
mactcp_status()
{
char dumpbuf[4000];
char * dumpp;
extern char * strend();
TCPiopb infoblk;
OSErr errcode;
struct TCPConnectionStats *statp;
memzero(&infoblk, sizeof(struct TCPiopb));
infoblk.ioCRefNum = ipp_refnum;
infoblk.csCode = TCPGlobalInfo;
/* used primarily for debugging purposes */
if (errcode = PBControl(&infoblk, (Boolean) FALSE)) {
;
}
statblk.ioCRefNum = ipp_refnum;
statblk.csCode = TCPStatus;
statblk.tcpStream = keydp->tcp_stream;
if (errcode = PBControl(&statblk, (Boolean) FALSE)) {
/*
getcontext(keydp);
tcp_err(errcode);
tcp_err() uses emdp
return(0);
instead, fall through and show last stat block gathered...
*/
/* statblk.csParam.status.connectionState = CLOSED; fix stat report */
/* no connection exists returns failure; TODO should cache closing stats? */
return(0);
}
statp = statblk.csParam.status.connStatPtr;
/* we hope dumpbuf does not get overwritten; this program protected by prayer
"I shot a pointer into the buffer, I hope the program does not suffer ..." */
dumpp = dumpbuf;
sprintf(dumpbuf, "Connection State: ");
dumpp = strend(dumpp);
/* reposition pointer to end to add more */
switch (statblk.csParam.status.connectionState) {
case CLOSED: {
sprintf(dumpp, "Closed\r");
break;
}
case SYNSENT: {
sprintf(dumpp, "Trying to Open\r");
break;
}
case SYNRCVD: {
sprintf(dumpp, "SYNRCVD\r");
break;
}
case ESTAB: {
sprintf(dumpp, "Established\r");
break;
}
case FINWAIT1: {
sprintf(dumpp, "Closing (FIN-WAIT 1)\r");
break;
}
case FINWAIT2: {
sprintf(dumpp, "Closing (FIN-WAIT 2)\r");
break;
}
case CLOSEWAIT: {
sprintf(dumpp, "Closing (Close Wait)\r");
break;
}
case CLOSING: {
sprintf(dumpp, "Closing\r");
break;
}
case LASTACK: {
sprintf(dumpp, "Closing (Last Ack)\r");
break;
}
case TIMEWAIT: {
sprintf(dumpp, "Closing (Time Wait)\r");
break;
}
default: {
sprintf(dumpp, "Closing\r");
}
}
dumpp = strend(dumpp);
sprintf(dumpp, "\r");
dumpp = strend(dumpp);
sprintf(dumpp, "Packets sent: %5U Resends: %5U\r",
statp->dataPktsSent, statp->dataPktsResent);
dumpp = strend(dumpp);
sprintf(dumpp, "Packets rcvd: %5U\r",
statp->dataPktsRcvd);
/* Re-rcvd: %5U Not for me: %5U */
dumpp = strend(dumpp);
/*
sprintf(dumpp, "Bad checksum: %5u No data: %5u Out of seq: %5u -- %u used\r",
tcpbadck, tcpnodata, tcpoutseq, tcpsoutseq);
dumpp = strend(dumpp);
*/
sprintf(dumpp, "Local Window: %5u HostWindow: %5u\r",
statblk.csParam.status.rcvWindow, statblk.csParam.status.sendWindow);
dumpp = strend(dumpp);
sprintf(dumpp, " ACK: %08X SEQ: %08X\r",
statblk.csParam.status.rcvNext, statblk.csParam.status.sendNext);
dumpp = strend(dumpp);
sprintf(dumpp, " Bytes Sent: %10U -- %u unacked\r",
statp->bytesSent, emdp->fillcount - emdp->waitcount);
dumpp = strend(dumpp);
sprintf(dumpp, " Bytes Rcvd: %10U\r",
statp->bytesRcvd);
dumpp = strend(dumpp);
fillwindow(TEXTOTHER, dumpbuf, (long) (dumpp - dumpbuf), monaco, 9, 0L);
/* TEXT types have 4 bytes of length in them */
}
/* free the memory associated with a MacTCP session */
tcpmemoryreclaim(twp)
struct winds * twp;
{
short cnt;
if (twp->mtstream)
free(twp->mtstream);
if (twp->rcvbuf)
free(twp->rcvbuf);
if (twp->sendbuf)
free(twp->sendbuf);
if (twp->tcp_conn)
free(twp->tcp_conn);
twp->mtstream = NULL;
twp->rcvbuf = NULL;
twp->sendbuf = NULL;
twp->tcp_conn = NULL;
}
#ifdef NOTMERGED
/* send MacTCP data waiting to be sent ... */
tcp_service()
{
struct winds ** conp = conns;
struct winds * conend = &conp[conncount];
register struct winds * twp;
while (conp < conend) {
twp = *conp++;
if (twp->conntype != CONN_MACTCP)
continue;
if (twp->closeflag) {
getcontext(twp);
mactcp_wrapup(); /* WARNING: twp may disappear, emdp may change! */
}
if (twp->send_wait) {
/* a packet is waiting for buffer; try to send again */
getcontext(twp);
mactcp_ex();
}
else if (twp->fillcount && (twp->fillcount == twp->waitcount)) {
/* SHOULD NEVER REACH THIS POINT! once was a symptom of
MacTCP async "let's waste some variables" behavior */
getcontext(twp);
mactcp_ex();
}
}
}
#endif
memzero(zptr, length)
register char * zptr;
int length;
{
while (length--)
*zptr++ = 0;
}
/* draw the packet counters */
tcp_drawcount(twp)
struct winds * twp;
{
OSErr errcode;
struct TCPConnectionStats *statp;
if (!twp->connopen)
return(0);
statblk.ioCRefNum = ipp_refnum;
statblk.csCode = TCPStatus;
statblk.tcpStream = twp->tcp_stream;
if (errcode = PBControl(&statblk, (Boolean) FALSE)) {
return(0);
}
statp = statblk.csParam.status.connStatPtr;
if (twp->in_cnt != statp->dataPktsRcvd) {
twp->in_cnt = statp->dataPktsRcvd;
getcontext(twp);
drawincount();
}
if (twp->out_cnt != (statp->dataPktsSent + statp->dataPktsResent)) {
twp->out_cnt = (statp->dataPktsSent + statp->dataPktsResent);
getcontext(twp);
if (twp->resends != statp->dataPktsResent) {
twp->resends = statp->dataPktsResent;
/* if (statblk.csParam.status.amtUnackedData != 0)
skip this test so even synced senders can note the acklessness... */
twp->resending = TRUE;
}
drawoutcount();
}
else {
if (twp->resending) {
if (statblk.csParam.status.amtUnackedData == 0) {
twp->resending = FALSE;
getcontext(twp);
drawoutcount();
}
}
}
}
mtcpurgent()
{
mactcpurgent = TRUE;
}
mtcpclrurgent()
{
mactcpurgent = 0;
}
beartrap()
{
SysBeep(5);
}